package com.springboot.fram.core.date;


import com.springboot.fram.core.lang.Utils;
import org.apache.commons.lang3.StringUtils;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * @author madman
 * @version 1.0
 * @date 2019/8/4 11:33
 * 时间处理工具类
 */
public class DateUtils {
    /**
     * 获取时间字符串，格式：yyyyMMddHHmmss
     */
    public static String getDateTime() {
        return format(DatePattern.DATETIME.getPattern());
    }

    /**
     * 获取时间字符串，格式：yyyyMMdd
     */
    public static String getDate() {
        return format(DatePattern.DATE.getPattern());
    }

    /**
     * 格式化指定日期
     *
     * @param pattern
     * @return
     */
    public static String format(Date date, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }

    /**
     * 格式化当前日期
     *
     * @param pattern
     * @return
     */
    private static String format(String pattern) {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }


    /**
     * 获取两个日期之间的天数
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static int differentDays(Date startDate, Date endDate) {
        if (startDate == null || endDate == null) {
            throw new RuntimeException("日期不能为空");
        }
        LocalDate localDate1 = date2LocalDate(startDate);
        LocalDate localDate2 = date2LocalDate(endDate);
        return Utils.safeLongToInt(localDate1.until(localDate2, ChronoUnit.DAYS));
    }

    public static LocalDate date2LocalDate(Date date) {
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDate localDate = instant.atZone(zoneId).toLocalDate();
        return localDate;
    }


    /**
     * 字符串按照指定格式转化为日期
     *
     * @param dateStr
     * @param formatStr
     * @return
     */
    public static Date stringTodate(String dateStr, String formatStr) {
        // 如果时间为空则默认当前时间
        Date date;
        SimpleDateFormat format = new SimpleDateFormat(formatStr);
        if (!StringUtils.isBlank(dateStr)) {
            try {
                date = format.parse(dateStr);
            } catch (ParseException e) {
                throw new RuntimeException("日期格式转换错误");
            }
        } else {
            // 当日期字符串为空的处理
           /* String timeTwo = format.format(new Date());
            try {
                date = format.parse(timeTwo);
            } catch (ParseException e) {
                throw new RuntimeException("日期格式转换错误");
            }*/
            throw new RuntimeException("字符串日期不能为空");
        }
        return date;
    }


    /**
     * 获取前几天时间
     *
     * @param date  日期
     * @param count 天数
     * @return
     */
    public static Date beforeDay(Date date, int count) {
        dateNotNull(date);
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, cal.get(Calendar.DATE) - count);
        date = cal.getTime();
        return date;
    }


    /**
     * 获取前几天的日期
     * 当前日期
     *
     * @param past
     * @return
     */
    public static Date beforeDay(int past) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) - past);
        Date today = calendar.getTime();
        return today;
    }


    /**
     * 获取几秒后的时间
     *
     * @param date    日期
     * @param seconds 秒
     * @return
     */
    public static Date afterSeconds(Date date, int seconds) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.SECOND, seconds);
        return calendar.getTime();
    }

    /**
     * 获取几分钟后的时间
     *
     * @param date   日期
     * @param minute 分钟
     * @return
     */
    public static Date afterMinute(Date date, int minute) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MINUTE, minute);
        return calendar.getTime();
    }

    /**
     * 获取几小时后的时间
     *
     * @param date 日期
     * @param hour 秒
     * @return
     */
    public static Date afterHour(Date date, int hour) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) + hour);
        return calendar.getTime();
    }


    /**
     * 获取时间后几天时间
     *
     * @param date  日期
     * @param count 天数
     * @return
     */
    public static Date afterDay(Date date, int count) {
        dateNotNull(date);
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, cal.get(Calendar.DATE) + count);
        date = cal.getTime();
        return date;
    }

    /**
     * 获取下一周的时间
     *
     * @param date
     * @return
     */
    public static Date nextWeek(Date date) {
        return nextWeek(date, 1);
    }


    /**
     * 获取下一周的时间
     *
     * @param date
     * @return
     */
    public static Date nextWeek(Date date, int week) {
        dateNotNull(date);
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_MONTH, cal.get(Calendar.DAY_OF_MONTH) + week * 7);
        date = cal.getTime();
        return date;
    }


    /**
     * 获取下一月的时间
     *
     * @param date
     * @return
     */
    public static Date nextMonth(Date date) {
        return nextMonth(date, 1);
    }

    /**
     * 获取下一月的时间
     *
     * @param date
     * @return
     */
    public static Date nextMonth(Date date, int month) {
        dateNotNull(date);
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, month);
        date = cal.getTime();
        return date;
    }

    /**
     * 获取上一月的时间
     *
     * @param date
     * @return
     */
    public static Date prevMonth(Date date) {
        return prevMonth(date, 1);
    }

    /**
     * 获取上一月的时间
     *
     * @param date
     * @return
     */
    public static Date prevMonth(Date date, int month) {
        dateNotNull(date);
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, -month);
        date = cal.getTime();
        return date;
    }

    /**
     * 获取下一年的时间
     *
     * @param date
     * @return
     */
    public static Date nextYear(Date date) {
        return nextYear(date, 1);
    }

    /**
     * 获取下一年的时间
     *
     * @param date
     * @return
     */
    public static Date nextYear(Date date, int year) {
        dateNotNull(date);
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) + year);
        date = cal.getTime();
        return date;
    }

    /**
     * 获取上一年的时间
     *
     * @param date
     * @return
     */
    public static Date prevYear(Date date) {
        return prevYear(date, 1);
    }

    /**
     * 获取上一年的时间
     *
     * @param date
     * @return
     */
    public static Date prevYear(Date date, int year) {
        dateNotNull(date);
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) - year);
        date = cal.getTime();
        return date;
    }

    /**
     * 日期不能为空
     *
     * @param date
     */
    public static void dateNotNull(Date date) {
        if (null == date) {
            throw new RuntimeException("日期不能为空");
        }
    }


    /**
     * 获取几天前的日期集合
     *
     * @param intervals intervals天内
     * @return 日期数组
     */
    public static List<Date> getBeforeDays(int intervals) {
        List<Date> pastDaysList = new ArrayList<>();
        for (int i = intervals - 1; i >= 0; i--) {
            pastDaysList.add(beforeDay(i));
        }
        return pastDaysList;
    }

    /**
     * 获取日期的24小时制
     *
     * @param time
     * @return：YYYY-MM
     */
    public static List<String> getDayHourList(String time, String resultFormatStr) {
        SimpleDateFormat sdf = new SimpleDateFormat(DatePattern.DATE.getPattern());
        // 声明保存日期集合
        List<String> list = new ArrayList<String>();
        try {
            // 转化成日期类型
            sdf.parse(time);
            int i = 23;
            String date;
            Date d;
            SimpleDateFormat sdfd = new SimpleDateFormat(DatePattern.DATE_HOUR.getPattern());
            SimpleDateFormat resSdf = new SimpleDateFormat(resultFormatStr);
            for (; i >= 0; i--) {
                if (String.valueOf(i).length() == 0) {
                    date = time + " 0" + i;
                } else {
                    date = time + " " + i;
                }
                d = sdfd.parse(date);
                list.add(resSdf.format(d));
            }
        } catch (ParseException e) {
            throw new RuntimeException("日期格式转换错误");
        }
        return list;
    }

    /**
     * 获取两个日期之间所有的天数集合
     *
     * @param startTime
     * @param endTime
     * @return：YYYY-MM
     */
    public static List<String> getDayList(String startTime, String endTime, String formatStr) {
        SimpleDateFormat sdf = new SimpleDateFormat(formatStr);
        // 声明保存日期集合
        List<String> list = new ArrayList<String>();
        try {
            // 转化成日期类型
            Date startDate = sdf.parse(startTime);
            Date endDate = sdf.parse(endTime);

            //用Calendar 进行日期比较判断
            Calendar calendar = Calendar.getInstance();
            while (startDate.getTime() <= endDate.getTime()) {
                // 把日期添加到集合
                list.add(sdf.format(startDate));
                // 设置日期
                calendar.setTime(startDate);
                //把日期增加一天
                calendar.add(Calendar.DATE, 1);
                // 获取增加后的日期
                startDate = calendar.getTime();
            }
        } catch (ParseException e) {
            throw new RuntimeException("日期格式转换错误");
        }
        return list;
    }

    /**
     * 获取两个日期之间所有的月份集合
     *
     * @param startTime
     * @param endTime
     * @return：YYYY-MM
     */
    public static List<String> getMonthList(String startTime, String endTime, String formatStr) {
        SimpleDateFormat sdf = new SimpleDateFormat(formatStr);
        // 声明保存日期集合
        List<String> list = new ArrayList<String>();
        try {
            // 转化成日期类型
            Date startDate = sdf.parse(startTime);
            Date endDate = sdf.parse(endTime);

            //用Calendar 进行日期比较判断
            Calendar calendar = Calendar.getInstance();
            while (startDate.getTime() <= endDate.getTime()) {
                // 把日期添加到集合
                list.add(sdf.format(startDate));
                // 设置日期
                calendar.setTime(startDate);
                //把日期增加一天
                calendar.add(Calendar.MONTH, 1);
                // 获取增加后的日期
                startDate = calendar.getTime();
            }
        } catch (ParseException e) {
            throw new RuntimeException("日期格式转换错误");
        }
        return list;
    }


    /**
     * 获取两个日期之间所有的年份集合
     *
     * @param startTime
     * @param endTime
     * @return：YYYY
     */
    public static List<String> getYearList(String startTime, String endTime, String formatStr) {
        SimpleDateFormat sdf = new SimpleDateFormat(formatStr);
        // 声明保存日期集合
        List<String> list = new ArrayList<String>();
        try {
            // 转化成日期类型
            Date startDate = sdf.parse(startTime);
            Date endDate = sdf.parse(endTime);

            //用Calendar 进行日期比较判断
            Calendar calendar = Calendar.getInstance();
            while (startDate.getTime() <= endDate.getTime()) {
                // 把日期添加到集合
                list.add(sdf.format(startDate));
                // 设置日期
                calendar.setTime(startDate);
                //把日期增加一天
                calendar.add(Calendar.YEAR, 1);
                // 获取增加后的日期
                startDate = calendar.getTime();
            }
        } catch (ParseException e) {
            throw new RuntimeException("日期格式转换错误");
        }
        return list;
    }

    /**
     * @param startTimeStr 格式
     * @param endTimeStr
     * @return
     * @Desc 获取两个时间之间的间隔天数
     */
    public static int getBetweenDays(String startTimeStr, String endTimeStr) {
        int betweenDays = 0;
        Date startTime = strToDateLong(startTimeStr);
        Date endTime = strToDateLong(endTimeStr);

        long start = startTime.getTime();
        long end = endTime.getTime();

        betweenDays = (int) (Math.abs(end - start) / (24 * 3600 * 1000));

        return betweenDays + 1;
    }

    public static Date strToDateLong(String strDate) {
        SimpleDateFormat formatter = new SimpleDateFormat(DatePattern.DATE.getPattern());
        ParsePosition pos = new ParsePosition(0);
        Date strtodate = formatter.parse(strDate, pos);
        return strtodate;
    }

    /**
     * 获取上月的开始时间
     *
     * @return
     */
    public static Date getBeginDayOfLastMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 2, 1);
        return getDayStartTime(calendar.getTime());
    }

    /**
     * 获取上月的结束时间
     *
     * @return
     */
    public static Date getEndDayOfLastMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 2, 1);
        int day = calendar.getActualMaximum(5);
        calendar.set(getNowYear(), getNowMonth() - 2, day);
        return getDayEndTime(calendar.getTime());
    }

    /**
     * 获取某个日期的结束时间
     *
     * @param d
     * @return
     */
    public static Timestamp getDayEndTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        if (null != d) {
            calendar.setTime(d);
        }
        calendar.set(calendar.get(Calendar.YEAR),
                calendar.get(Calendar.MONTH),
                calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取某个日期的开始时间
     *
     * @param d
     * @return
     */
    public static Timestamp getDayStartTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        if (null != d) {
            calendar.setTime(d);
        }
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取今年是哪一年
     *
     * @return
     */
    public static Integer getNowYear() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return Integer.valueOf(gc.get(Calendar.YEAR));
    }


    /**
     * 获取本月是哪一月
     *
     * @return
     */
    public static int getNowMonth() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return gc.get(Calendar.MONTH) + 1;
    }

    /**
     * 获取今天开始时间
     */
    private static Long getTodayStartTime() {
        Calendar todayStart = Calendar.getInstance();
        todayStart.set(Calendar.HOUR_OF_DAY, 0);
        todayStart.set(Calendar.MINUTE, 0);
        todayStart.set(Calendar.SECOND, 0);
        todayStart.set(Calendar.MILLISECOND, 0);
        return todayStart.getTimeInMillis();
    }

    /**
     * 获取今天结束时间
     */
    private static Long getTodayEndTime() {
        Calendar todayEnd = Calendar.getInstance();
        todayEnd.set(Calendar.HOUR, 23);
        todayEnd.set(Calendar.MINUTE, 59);
        todayEnd.set(Calendar.SECOND, 59);
        todayEnd.set(Calendar.MILLISECOND, 999);
        return todayEnd.getTime().getTime();
    }


    /**
     * 指定年月的开始日期
     *
     * @param year
     * @param month
     * @return
     */
    public static Date getBeginTime(int year, int month) {
        YearMonth yearMonth = YearMonth.of(year, month);
        LocalDate localDate = yearMonth.atDay(1);
        LocalDateTime startOfDay = localDate.atStartOfDay();
        ZonedDateTime zonedDateTime = startOfDay.atZone(ZoneId.of("Asia/Shanghai"));
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * 指定年月的结束日期
     *
     * @param year
     * @param month
     * @return
     */
    public static Date getEndTime(int year, int month) {
        YearMonth yearMonth = YearMonth.of(year, month);
        LocalDate endOfMonth = yearMonth.atEndOfMonth();
        LocalDateTime localDateTime = endOfMonth.atTime(23, 59, 59, 999);
        ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.of("Asia/Shanghai"));
        return Date.from(zonedDateTime.toInstant());
    }

    /**
     * get current timestamp
     *
     * @return
     */
    public static long getCurrentTimestamp() {
        long unixTimestamp = Instant.now().getEpochSecond();
        return unixTimestamp;
    }


    /**
     * 取得两个日期间隔秒数（日期1-日期2）
     *
     * @param one 日期1
     * @param two 日期2
     * @return 间隔秒数
     */
    public static long getDiffSeconds(Date one, Date two) {
        Calendar sysDate = new GregorianCalendar();
        sysDate.setTime(one);
        Calendar failDate = new GregorianCalendar();
        failDate.setTime(two);
        return (sysDate.getTimeInMillis() - failDate.getTimeInMillis()) / 1000;
    }

    /**
     * 取得两个日期间隔分钟数（日期1-日期2）
     *
     * @param one
     * @param two
     * @return
     */
    public static long getDiffMinutes(Date one, Date two) {
        Calendar sysDate = new GregorianCalendar();
        sysDate.setTime(one);
        Calendar failDate = new GregorianCalendar();
        failDate.setTime(two);
        return (sysDate.getTimeInMillis() - failDate.getTimeInMillis()) / (60 * 1000);
    }

    /**
     * 取得两个日期间隔小时数（日期1-日期2）
     *
     * @param one
     * @param two
     * @return
     */
    public static long getDiffHours(Date one, Date two) {
        Calendar sysDate = new GregorianCalendar();
        sysDate.setTime(one);
        Calendar failDate = new GregorianCalendar();
        failDate.setTime(two);
        return (sysDate.getTimeInMillis() - failDate.getTimeInMillis()) / (3600 * 1000);
    }

    /**
     * 取得两个日期的间隔天数
     *
     * @param one
     * @param two
     * @return 间隔天数
     */
    public static long getDiffDays(Date one, Date two) {
        Calendar sysDate = new GregorianCalendar();
        sysDate.setTime(one);
        Calendar failDate = new GregorianCalendar();
        failDate.setTime(two);
        return (sysDate.getTimeInMillis() - failDate.getTimeInMillis()) / (24 * 60 * 60 * 1000);
    }


    //  格式化转换

    /**
     * 将日期时间字符串转换为{@link java.time.LocalDateTime}对象
     *
     * @param dateTime    日期时间字符串
     * @param datePattern 格式化枚举
     * @return LocalDateTime 对象
     */
    public static LocalDateTime parseDateTime(String dateTime, DatePattern datePattern) {
        return LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern(datePattern.getPattern()));
    }

    /**
     * 将日期字符串转换为{@link java.time.LocalDate}对象
     *
     * @param date        日期字符串
     * @param datePattern 格式化枚举
     * @return LocalDate 对象
     */
    public static LocalDate parseDate(String date, DatePattern datePattern) {
        return LocalDate.parse(date, DateTimeFormatter.ofPattern(datePattern.getPattern()));
    }

    /**
     * 将时间字符串转换为{@link java.time.LocalTime}对象
     *
     * @param date        时间字符串
     * @param datePattern 格式化枚举
     * @return LocalTime 对象
     */
    public static LocalTime parseTime(String date, DatePattern datePattern) {
        return LocalTime.parse(date, DateTimeFormatter.ofPattern(datePattern.getPattern()));
    }

    /**
     * 根据特定格式格式化日期时间
     *
     * @param localDateTime 本地日期时间
     * @param datePattern   格式化枚举
     * @return 日期时间字符串
     */
    public static String formatDateTime(LocalDateTime localDateTime, DatePattern datePattern) {
        return localDateTime.format(DateTimeFormatter.ofPattern(datePattern.getPattern()));
    }

    /**
     * 根据特定格式格式化日期时间
     *
     * @param localDate   本地日期时间
     * @param datePattern 格式化枚举
     * @return 日期时间字符串
     */
    public static String formatDate(LocalDate localDate, DatePattern datePattern) {
        return localDate.format(DateTimeFormatter.ofPattern(datePattern.getPattern()));
    }

    /**
     * 根据特定格式格式化日期时间
     *
     * @param localTime   本地日期时间
     * @param datePattern 格式化枚举
     * @return 日期时间字符串
     */
    public static String formatTime(LocalTime localTime, DatePattern datePattern) {
        return localTime.format(DateTimeFormatter.ofPattern(datePattern.getPattern()));
    }

    /**
     * Date类型转为本地日期时间
     *
     * @param date Date类
     * @return 本地日期时间
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * 本地日期时间转为Date类型
     *
     * @param localDateTime 本地日期时间
     * @return Date类型
     */
    public static Date localDateTimeToDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }


}
